package com.dlc.shop.seckill.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.dlc.shop.bean.app.dto.ShopCartItemDiscountDto;
import com.dlc.shop.bean.app.dto.ShopCartItemDto;
import com.dlc.shop.bean.app.dto.ShopCartOrderDto;
import com.dlc.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.dlc.shop.bean.event.PayManagerEvent;
import com.dlc.shop.bean.model.Order;
import com.dlc.shop.bean.model.OrderItem;
import com.dlc.shop.bean.model.PayInfo;
import com.dlc.shop.common.util.DataBatchHandleUtil;
import com.dlc.shop.dao.OrderMapper;
import com.dlc.shop.dao.PayInfoMapper;
import com.dlc.shop.manager.impl.StockManager;
import com.dlc.shop.seckill.common.service.SeckillOrderService;
import com.dlc.shop.service.FlowLogService;
import com.dlc.shop.service.OrderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 秒杀订单
 *
 * @author LGH
 * @date 2019-08-28 09:36:59
 */
@Slf4j
@Service
@AllArgsConstructor
public class SeckillOrderServiceImpl implements SeckillOrderService {

    private final PayInfoMapper payInfoMapper;

    private final OrderMapper orderMapper;

    private final OrderService orderService;

    private final StockManager stockManager;

    private final ApplicationEventPublisher eventPublisher;

    private FlowLogService flowLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submit(ShopCartOrderMergerDto dto) {
        if (StrUtil.isNotBlank(dto.getLocale())) {
            LocaleContextHolder.setLocale(new Locale(dto.getLocale()));
        }
        ShopCartOrderDto shopCartOrderDto = dto.getShopCartOrders().get(0);
        ShopCartItemDiscountDto shopCartItemDiscountDto = shopCartOrderDto.getShopCartItemDiscounts().get(0);
        ShopCartItemDto shopCartItemDto = shopCartItemDiscountDto.getShopCartItems().get(0);
        shopCartItemDto.setActivityId(dto.getSeckillId());
        shopCartItemDto.setActivityType(dto.getOrderType().value());
        String orderNumber = shopCartOrderDto.getOrderNumber();
        // 创建订单相关信息
        orderService.submit(dto);
        // 插入流量数据
        flowLogService.saveSubmitOrder(dto.getOrderFlowLogParam(), dto.getUserId(), String.valueOf(orderNumber));
        return orderNumber;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrderUnpayOrderByTime() {
        // 查询出微信or支付宝支付并且为二维码支付的，失效掉对应支付二维码
        List<PayInfo> filterPayInfo = payInfoMapper.listByPayTypeAndTime();
        // 失效二维码
        if (CollectionUtils.isNotEmpty(filterPayInfo)) {
            eventPublisher.publishEvent(new PayManagerEvent(filterPayInfo));
        }
        Date cancelTime = DateUtil.offsetMinute(new Date(), 2).toJdkDate();
        List<Order> orderList = orderMapper.listUnPayOrder(cancelTime);
        if (CollUtil.isEmpty(orderList)) {
            log.info("没有查询到超时未的支付秒杀订单");
            return;
        }

        List<String> orderNumbers = new ArrayList<>(orderList.size());
        // 还原库存
        for (Order order : orderList) {
            if (CollUtil.isEmpty(order.getOrderItems())) {
                continue;
            }
            OrderItem orderItem = order.getOrderItems().get(0);
            orderNumbers.add(orderItem.getOrderNumber());
            // 还原库存可以重复执行，lua有幂等处理，只会还原一次
            stockManager.rollbackSecKillStock(orderItem.getActivityId(), orderItem.getSkuId(), orderItem.getProdCount(), orderItem.getOrderNumber(), orderItem.getUserId(), orderItem.getStockPointId());
        }
        // 修改订单状态
        DataBatchHandleUtil.batchSplitInsert(orderNumbers, orderMapper::batchCancelSeckillOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelUnpayOrderByOrderNumber(String orderNumber) {
        Order order = orderService.getOrderAndOrderItemByOrderNumber(orderNumber);
        if(Objects.isNull(order) || CollUtil.isEmpty(order.getOrderItems())){
            return;
        }
        OrderItem orderItem = order.getOrderItems().get(0);
        stockManager.rollbackSecKillStock(orderItem.getActivityId(), orderItem.getSkuId(), orderItem.getProdCount(), orderItem.getOrderNumber(), orderItem.getUserId(), orderItem.getStockPointId());
    }
}
